<template>
  <div class="qr-code-scanner">
    <!-- 扫描器容器 -->
    <div
      v-show="showScanner"
      ref="scannerRef"
      class="qr-code-scanner__container"
    >
      <!-- 视频预览 -->
      <video
        ref="videoRef"
        class="qr-code-scanner__video"
        autoplay
        muted
        playsinline
      />
      
      <!-- 扫描框 -->
      <div class="qr-code-scanner__overlay">
        <div class="qr-code-scanner__scan-area">
          <div class="qr-code-scanner__corners">
            <div class="qr-code-scanner__corner qr-code-scanner__corner--top-left" />
            <div class="qr-code-scanner__corner qr-code-scanner__corner--top-right" />
            <div class="qr-code-scanner__corner qr-code-scanner__corner--bottom-left" />
            <div class="qr-code-scanner__corner qr-code-scanner__corner--bottom-right" />
          </div>
          <div class="qr-code-scanner__scan-line" />
        </div>
      </div>

      <!-- 控制按钮 -->
      <div class="qr-code-scanner__controls">
        <van-button
          icon="photo-o"
          type="primary"
          round
          @click="selectImage"
        >
          相册
        </van-button>
        
        <van-button
          :icon="flashEnabled ? 'flash' : 'flash-o'"
          type="primary"
          round
          @click="toggleFlash"
        >
          {{ flashEnabled ? '关闭' : '开启' }}闪光灯
        </van-button>
        
        <van-button
          icon="replay"
          type="primary"
          round
          @click="switchCamera"
        >
          切换
        </van-button>
      </div>

      <!-- 提示信息 -->
      <div class="qr-code-scanner__tips">
        <p>{{ tips }}</p>
      </div>
    </div>

    <!-- 结果显示 -->
    <van-popup
      v-model:show="showResult"
      position="bottom"
      :style="{ height: '40%' }"
      round
    >
      <div class="qr-code-scanner__result">
        <div class="qr-code-scanner__result-header">
          <h3>扫描结果</h3>
          <van-icon name="cross" @click="closeResult" />
        </div>
        <div class="qr-code-scanner__result-content">
          <div class="qr-code-scanner__result-text">{{ scanResult }}</div>
          <div class="qr-code-scanner__result-actions">
            <van-button
              type="primary"
              block
              @click="handleResult"
            >
              {{ getActionText() }}
            </van-button>
            <van-button
              block
              @click="copyResult"
            >
              复制内容
            </van-button>
          </div>
        </div>
      </div>
    </van-popup>

    <!-- 隐藏的文件输入 -->
    <input
      ref="fileInputRef"
      type="file"
      accept="image/*"
      style="display: none"
      @change="handleFileSelect"
    />

    <!-- 画布（用于图像处理） -->
    <canvas
      ref="canvasRef"
      style="display: none"
    />
  </div>
</template>

<script>
import { ref, onMounted, onUnmounted, defineComponent } from 'vue'
import { Toast } from 'vant'
import { copyToClipboard } from '@/utils/useClipboard'

export default defineComponent({
  name: 'QrCodeScanner',
  props: {
    /**
     * 是否显示扫描器
     */
    modelValue: {
      type: Boolean,
      default: false
    },
    /**
     * 扫描成功后是否自动关闭
     */
    autoClose: {
      type: Boolean,
      default: true
    },
    /**
     * 扫描间隔（毫秒）
     */
    scanInterval: {
      type: Number,
      default: 300
    },
    /**
     * 提示信息
     */
    tips: {
      type: String,
      default: '将二维码放入框内，即可自动扫描'
    },
    /**
     * 是否启用连续扫描
     */
    continuous: {
      type: Boolean,
      default: false
    },
    /**
     * 相机约束
     */
    constraints: {
      type: Object,
      default: () => ({
        video: {
          width: { ideal: 1280 },
          height: { ideal: 720 },
          facingMode: 'environment' // 后置摄像头
        }
      })
    }
  },
  emits: ['update:modelValue', 'scan', 'error'],
  setup(props, { emit }) {
    const scannerRef = ref(null)
    const videoRef = ref(null)
    const canvasRef = ref(null)
    const fileInputRef = ref(null)
    
    const showScanner = ref(false)
    const showResult = ref(false)
    const scanResult = ref('')
    const flashEnabled = ref(false)
    const currentFacingMode = ref('environment')
    
    let mediaStream = null
    let scanTimer = null
    let qrCodeReader = null

    /**
     * 初始化二维码读取器
     */
    const initQrCodeReader = async () => {
      try {
        // 动态导入 qr-scanner 库
        const QrScanner = await import('qr-scanner')
        qrCodeReader = QrScanner.default || QrScanner
      } catch (error) {
        console.error('Failed to load QR scanner:', error)
        Toast.fail('二维码扫描功能不可用')
      }
    }

    /**
     * 启动相机
     */
    const startCamera = async () => {
      try {
        if (mediaStream) {
          stopCamera()
        }

        const constraints = {
          ...props.constraints,
          video: {
            ...props.constraints.video,
            facingMode: currentFacingMode.value
          }
        }

        mediaStream = await navigator.mediaDevices.getUserMedia(constraints)
        
        if (videoRef.value) {
          videoRef.value.srcObject = mediaStream
          await videoRef.value.play()
          startScanning()
        }
      } catch (error) {
        console.error('Failed to start camera:', error)
        emit('error', error)
        Toast.fail('无法访问摄像头')
      }
    }

    /**
     * 停止相机
     */
    const stopCamera = () => {
      if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop())
        mediaStream = null
      }
      stopScanning()
    }

    /**
     * 开始扫描
     */
    const startScanning = () => {
      if (!qrCodeReader || !videoRef.value) return

      scanTimer = setInterval(async () => {
        try {
          const result = await scanQrCode()
          if (result) {
            handleScanSuccess(result)
          }
        } catch (error) {
          // 扫描失败，继续下一次扫描
        }
      }, props.scanInterval)
    }

    /**
     * 停止扫描
     */
    const stopScanning = () => {
      if (scanTimer) {
        clearInterval(scanTimer)
        scanTimer = null
      }
    }

    /**
     * 扫描二维码
     */
    const scanQrCode = async () => {
      if (!videoRef.value || !canvasRef.value || !qrCodeReader) return null

      const video = videoRef.value
      const canvas = canvasRef.value
      const ctx = canvas.getContext('2d')

      // 设置画布尺寸
      canvas.width = video.videoWidth
      canvas.height = video.videoHeight

      // 绘制视频帧到画布
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

      try {
        // 使用 qr-scanner 扫描画布
        const result = await qrCodeReader.scanImage(canvas)
        return result
      } catch (error) {
        return null
      }
    }

    /**
     * 扫描成功处理
     */
    const handleScanSuccess = (result) => {
      scanResult.value = result
      showResult.value = true
      
      emit('scan', result)
      
      if (!props.continuous) {
        stopScanning()
      }
      
      if (props.autoClose && !props.continuous) {
        setTimeout(() => {
          showScanner.value = false
          emit('update:modelValue', false)
        }, 1000)
      }
    }

    /**
     * 切换闪光灯
     */
    const toggleFlash = async () => {
      if (!mediaStream) return

      try {
        const track = mediaStream.getVideoTracks()[0]
        const capabilities = track.getCapabilities()
        
        if (capabilities.torch) {
          await track.applyConstraints({
            advanced: [{ torch: !flashEnabled.value }]
          })
          flashEnabled.value = !flashEnabled.value
        } else {
          Toast.fail('设备不支持闪光灯')
        }
      } catch (error) {
        console.error('Failed to toggle flash:', error)
        Toast.fail('闪光灯控制失败')
      }
    }

    /**
     * 切换摄像头
     */
    const switchCamera = () => {
      currentFacingMode.value = currentFacingMode.value === 'environment' ? 'user' : 'environment'
      startCamera()
    }

    /**
     * 选择图片
     */
    const selectImage = () => {
      fileInputRef.value?.click()
    }

    /**
     * 处理文件选择
     */
    const handleFileSelect = async (event) => {
      const file = event.target.files[0]
      if (!file) return

      try {
        const result = await scanImageFile(file)
        if (result) {
          handleScanSuccess(result)
        } else {
          Toast.fail('未识别到二维码')
        }
      } catch (error) {
        console.error('Failed to scan image:', error)
        Toast.fail('图片扫描失败')
      }
      
      // 清空文件输入
      event.target.value = ''
    }

    /**
     * 扫描图片文件
     */
    const scanImageFile = async (file) => {
      if (!qrCodeReader) return null

      try {
        const result = await qrCodeReader.scanImage(file)
        return result
      } catch (error) {
        return null
      }
    }

    /**
     * 获取操作按钮文本
     */
    const getActionText = () => {
      const result = scanResult.value
      
      if (result.startsWith('http://') || result.startsWith('https://')) {
        return '打开链接'
      } else if (result.startsWith('tel:')) {
        return '拨打电话'
      } else if (result.startsWith('mailto:')) {
        return '发送邮件'
      } else if (result.startsWith('wifi:')) {
        return '连接WiFi'
      } else {
        return '查看详情'
      }
    }

    /**
     * 处理扫描结果
     */
    const handleResult = () => {
      const result = scanResult.value
      
      if (result.startsWith('http://') || result.startsWith('https://')) {
        window.open(result, '_blank')
      } else if (result.startsWith('tel:')) {
        window.location.href = result
      } else if (result.startsWith('mailto:')) {
        window.location.href = result
      } else {
        // 其他类型的处理
        Toast.success('已处理扫描结果')
      }
      
      closeResult()
    }

    /**
     * 复制结果
     */
    const copyResult = async () => {
      try {
        await copyToClipboard(scanResult.value)
        Toast.success('已复制到剪贴板')
      } catch (error) {
        Toast.fail('复制失败')
      }
    }

    /**
     * 关闭结果弹窗
     */
    const closeResult = () => {
      showResult.value = false
      if (props.continuous) {
        startScanning()
      }
    }

    /**
     * 监听显示状态变化
     */
    const watchShowScanner = () => {
      if (props.modelValue) {
        showScanner.value = true
        startCamera()
      } else {
        showScanner.value = false
        stopCamera()
      }
    }

    onMounted(async () => {
      await initQrCodeReader()
      watchShowScanner()
    })

    onUnmounted(() => {
      stopCamera()
    })

    return {
      scannerRef,
      videoRef,
      canvasRef,
      fileInputRef,
      showScanner,
      showResult,
      scanResult,
      flashEnabled,
      toggleFlash,
      switchCamera,
      selectImage,
      handleFileSelect,
      getActionText,
      handleResult,
      copyResult,
      closeResult
    }
  }
})
</script>

<style lang="scss" scoped>
.qr-code-scanner {
  &__container {
    position: relative;
    width: 100%;
    height: 100vh;
    background-color: #000;
    overflow: hidden;
  }

  &__video {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  &__overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
  }

  &__scan-area {
    position: relative;
    width: 250px;
    height: 250px;
    border: 2px solid rgba(255, 255, 255, 0.3);
    background-color: transparent;
  }

  &__corners {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }

  &__corner {
    position: absolute;
    width: 20px;
    height: 20px;
    border: 3px solid #1989fa;

    &--top-left {
      top: -3px;
      left: -3px;
      border-right: none;
      border-bottom: none;
    }

    &--top-right {
      top: -3px;
      right: -3px;
      border-left: none;
      border-bottom: none;
    }

    &--bottom-left {
      bottom: -3px;
      left: -3px;
      border-right: none;
      border-top: none;
    }

    &--bottom-right {
      bottom: -3px;
      right: -3px;
      border-left: none;
      border-top: none;
    }
  }

  &__scan-line {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, #1989fa, transparent);
    animation: scan 2s linear infinite;
  }

  &__controls {
    position: absolute;
    bottom: 100px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 20px;
    z-index: 10;

    .van-button {
      min-width: 80px;
      background-color: rgba(0, 0, 0, 0.6);
      border-color: rgba(255, 255, 255, 0.3);
      color: #fff;

      &:hover {
        background-color: rgba(0, 0, 0, 0.8);
      }
    }
  }

  &__tips {
    position: absolute;
    bottom: 40px;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    text-align: center;
    font-size: 14px;
    z-index: 10;

    p {
      margin: 0;
      padding: 8px 16px;
      background-color: rgba(0, 0, 0, 0.6);
      border-radius: 16px;
    }
  }

  &__result {
    padding: 20px;

    &-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 20px;

      h3 {
        margin: 0;
        font-size: 18px;
        font-weight: 600;
        color: #323233;
      }

      .van-icon {
        font-size: 20px;
        color: #969799;
        cursor: pointer;
      }
    }

    &-content {
      .van-button {
        margin-bottom: 12px;

        &:last-child {
          margin-bottom: 0;
        }
      }
    }

    &-text {
      padding: 16px;
      background-color: #f7f8fa;
      border-radius: 8px;
      font-size: 14px;
      line-height: 1.5;
      color: #323233;
      word-break: break-all;
      margin-bottom: 20px;
      max-height: 120px;
      overflow-y: auto;
    }

    &-actions {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
  }
}

@keyframes scan {
  0% {
    top: 0;
  }
  100% {
    top: 100%;
  }
}
</style>